package admin

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/model"
	"config-client-v1/utils/tools"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"time"
)

type FSController struct {
}

// List FS列表
func (con FSController) List(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		Name string `json:"name"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Where("del = 0 AND project_id = ?", userToken.ProjectID)
	if param.Name != "" {
		tx.Where("name = ?", param.Name)
	}
	var count int64
	list := make([]model.FSEquip, 0)
	err = tx.Model(&model.FSEquip{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("id ASC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

// Save FS保存
func (con FSController) Save(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := &model.FSEquip{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 " + err.Error(),
			"data":    err.Error(),
		})
		return
	}

	param.ProjectID = userToken.ProjectID
	err = param.ValidateBase()
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": err.Error(),
			"data":    param,
		})
		return
	}

	now := tools.GetNow()
	if param.ID == 0 {
		usedCode := make([]string, 0)
		err = model.DB.Model(&model.FSEquip{}).Where("project_id = ?", userToken.ProjectID).Pluck("code1", &usedCode).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		allCode := model.AllCode1()
		availableCode := model.GetAvailableCode(allCode, usedCode)
		if len(availableCode) == 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "已无可用的通信代码",
			})
			return
		}
		param.Code1 = availableCode[0]
		param.RunningState = 4
		param.CreateTime = &now
		param.UpdateTime = &now
		err = model.DB.Omit("FSModule").Create(&param).Error
	} else {
		old := &model.FSEquip{}
		exist, err1 := old.Exists(param.ID)
		if !exist {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数 id",
				"data":    err1,
			})
			return
		}
		param.RunningState = old.RunningState
		param.UpdateTime = &now
		err = model.DB.Omit("FSModule").Model(&model.FSEquip{}).Where("id = ?", param.ID).Select("*").Omit("id", "project_id", "code", "detail", "create_time", "del").Updates(&param).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		err = model.SyncFSEquipToMem(param.ID)
		j_log.LogInfo([]interface{}{fmt.Sprintf("更新FSE内存数据 fs_id=%d, %v", 0, err)})
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "SyncFSEquipToMem 同步内存数据失败 " + err.Error(),
				"data":    map[string]interface{}{},
			})
			return
		}
		if old.Stage == 0 && param.Stage == 1 {
			// 切换运行模式, 自动运行同步
			fse, ok := model.RunningFSMap.Get(param.ID)
			if ok && fse.RunningState == 2 {
				go func(fse *model.FSEquip) {
					time.Sleep(1 * time.Second)
					data := model.GenFSFrameData0601()
					_, err = fse.Write(data)
					if err != nil {
						j_log.LogError([]interface{}{"首次握手tcp发送失败", fse.Name, fse.IP, fse.Port, err.Error()})
						return
					}
					j_log.LogInfo([]interface{}{"首次握手tcp发送成功", fse.Name, fse.IP, fse.Port})
				}(fse)
			}
		} else if old.Stage == 1 && param.Stage == 0 {
			// 切换组态模式, 自动获取数据规模
			fse, ok := model.RunningFSMap.Get(param.ID)
			if ok && fse.RunningState == 2 {
				go fse.DataScaleGet()
			}
		}
	}

	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

// Detail FS详情
func (con FSController) Detail(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse := model.FSEquip{}

	err = model.DB.Preload("FSModule", func(db *gorm.DB) *gorm.DB {
		return db.Preload("FrameItem", func(db2 *gorm.DB) *gorm.DB {
			return db2.Order("code4 ASC")
		}).Order("code2 ASC,code3 ASC")
	}).Where("id = ?", param.FSID).First(&fse).Error

	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	//jsonB, _ := json.MarshalIndent(&fse, "", "  ")
	//jsonB, _ := json.Marshal(&info)
	//_ = tools.WriteStringToFile(string(jsonB), fmt.Sprintf("fse-%d.json", fse.ID), "w")
	fse.CalculateDataScale()
	scaleText := fmt.Sprintf("数据规模: AI=%d, DI=%d, AQ=%d, DQ=%d, Other=%d, EData=%d, 泵组电磁阀=%d, 增压泵电磁阀=%d, 电调阀=%d, 压力电磁阀=%d, 电源模块=%d, 电源状态=%d, 模态=%d, 诊断=%d",
		fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other, fse.DS.EData, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Diantiao, fse.DS.Pressure, fse.DS.Power, fse.DS.PowerState, fse.DS.ModeCollect, fse.DS.Diag)
	fse.FSModule = make([]*model.FSModule, 0)
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"scaleText": scaleText,
			"info":      fse,
		},
	})
}

func (con FSController) DataScale(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	if ctx.Request.Method == "POST" {
		err := ctx.ShouldBindBodyWith(&param, binding.JSON)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数",
				"data":    err.Error(),
			})
			return
		}
	} else {
		FSID := ctx.Query("fs_id")
		param.FSID, _ = strconv.Atoi(FSID)
	}

	fse := model.FSEquip{}
	err := model.DB.Preload("FSModule", func(db *gorm.DB) *gorm.DB {
		return db.Preload("FrameItem")
	}).Where("id = ?", param.FSID).First(&fse).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	fse.CalculateDataScale()
	scaleText := fmt.Sprintf("数据规模: AI=%d, DI=%d, AQ=%d, DQ=%d, Other=%d, EData=%d, 泵组电磁阀=%d, 增压泵电磁阀=%d, 压力电磁阀=%d",
		fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other, fse.DS.EData, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Pressure)
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"scaleText": scaleText,
		},
	})
}

// Delete FS删除
func (con FSController) Delete(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	info := model.FSEquip{}
	err = model.DB.Where("id = ?", param.FSID).Limit(1).Find(&info).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	if info.ID == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 fs_id",
			"data":    "",
		})
		return
	}

	err = model.DB.Transaction(func(tx *gorm.DB) error {
		err = tx.Where("id = ?", param.FSID).Delete(&model.FSEquip{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("fs_id = ?", param.FSID).Delete(&model.FSModule{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("fs_id = ?", param.FSID).Delete(&model.FrameItem{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("project_id = ?", info.ProjectID).Delete(&model.UploadHistory{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("project_id = ?", info.ProjectID).Delete(&model.CommandHistory{}).Error
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    10,
			"message": err.Error(),
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con FSController) UpdateStage(ctx *gin.Context) {
	param := struct {
		ID    int   `json:"id" binding:"required"`
		Stage uint8 `json:"stage"` // 0.组态阶段 1.运行阶段
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数" + err.Error(),
			"data":    err.Error(),
		})
		return
	}

	old := &model.FSEquip{}
	exist, err1 := old.Exists(param.ID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 id",
			"data":    err1,
		})
		return
	}
	if param.Stage != 0 {
		param.Stage = 1
	}
	err = model.DB.Model(&model.FSEquip{}).Where("id = ?", param.ID).Update("stage", param.Stage).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = model.SyncFSEquipToMem(param.ID)
	j_log.LogInfo([]interface{}{fmt.Sprintf("更新FSE内存数据 fs_id=%d, %v", 0, err)})
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "SyncFSEquipToMem 同步内存数据失败 " + err.Error(),
			"data":    map[string]interface{}{},
		})
		return
	}
	if old.Stage == 0 && param.Stage == 1 {
		// 切换运行模式, 自动运行同步
		fse, ok := model.RunningFSMap.Get(param.ID)
		if ok && fse.RunningState == 2 {
			go func(fse *model.FSEquip) {
				time.Sleep(1 * time.Second)
				data := model.GenFSFrameData0601()
				_, err = fse.Write(data)
				if err != nil {
					j_log.LogError([]interface{}{"首次握手tcp发送失败", fse.Name, fse.IP, fse.Port, err.Error()})
					return
				}
				j_log.LogInfo([]interface{}{"首次握手tcp发送成功", fse.Name, fse.IP, fse.Port})
			}(fse)
		}
	} else if old.Stage == 1 && param.Stage == 0 {
		// 切换组态模式, 自动获取数据规模
		fse, ok := model.RunningFSMap.Get(param.ID)
		if ok && fse.RunningState == 2 {
			go fse.DataScaleGet()
		}
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

// FSStart FS运行
func (con FSController) FSStart(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fseExist, ok := model.RunningFSMap.Get(param.FSID)
	if ok && fseExist.RunningState != 4 {
		j_log.LogError([]interface{}{"FS设备忙碌中, 不可重复运行", fseExist.Name, fseExist.IP, fseExist.Port, fseExist.Detail})
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备忙碌中,不可重复运行" + fseExist.Detail,
		})
		return
	}

	fse := &model.FSEquip{}
	err = model.DB.Preload("FSModule",
		func(tx *gorm.DB) *gorm.DB {
			return tx.Preload("FrameItem").Order("code2 ASC,code3 ASC")
		}).
		Where("id = ? AND project_id = ?", param.FSID, userToken.ProjectID).Limit(1).Find(fse).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	if fse.ID == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的 fs_id",
		})
		return
	}
	if model.RunningProject.ID != 0 && fse.ProjectID != model.RunningProject.ID {
		j_log.LogError([]interface{}{fse.Name, "只能运行一个工程", fse.ProjectID})
		ctx.JSON(200, gin.H{
			"code":    10,
			"message": "只能运行一个工程",
			"data": map[string]interface{}{
				"running_project_id": model.RunningProject.ID,
				"current_project_id": fse.ProjectID,
			},
		})
		return
	}

	err = model.ProjectStartHook(fse.ProjectID)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
		})
		return
	}

	fse.CalculateDataScale()
	model.RunningFSMap.Set(fse.ID, fse)

	fse.RunningState = 1 // 正在启动
	_ = fse.UpdateRunningState(1, "正在启动")
	model.WSClientMap.BroadCastEquipRunningState("fse", fse.ID, 1)
	err = fse.UpdateVariablesMap()
	if err != nil {
		j_log.LogError([]interface{}{"fse更新变量map失败", fse.Name})
	}
	go fse.RunFSTcpClient()

	startTime := time.Now()
	for {
		time.Sleep(100 * time.Millisecond)
		if fse.RunningState == 2 {
			break
		}
		if time.Since(startTime) > time.Second*5 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "启动失败, 运行超时",
				"data": map[string]interface{}{
					"signal_state": fse.RunningState,
					"detail":       fse.Detail,
				},
			})
			_ = model.SysAlertSave(&model.SysAlert{
				ProjectID:  fse.ProjectID,
				Const:      "ALERT_FS",
				Alert:      "自研设备启动超时",
				RelationID: fse.ID,
			})
			return
		}
	}
	if fse.Stage == 1 {
		go func(fse *model.FSEquip) {
			time.Sleep(1 * time.Second)
			data := model.GenFSFrameData0601()
			_, err = fse.Write(data)
			if err != nil {
				j_log.LogError([]interface{}{"首次握手tcp发送失败", fse.Name, fse.IP, fse.Port, err.Error()})
				return
			}
			j_log.LogInfo([]interface{}{"首次握手tcp发送成功", fse.Name, fse.IP, fse.Port})
		}(fse)
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"running_state": 2,
		},
	})
}

// FSStop FS停止
func (con FSController) FSStop(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		j_log.LogError([]interface{}{"当前FS设备TCP未连接"})
		fse = &model.FSEquip{ID: param.FSID}
		_ = fse.UpdateRunningState(4, "已停止")
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": fmt.Sprintf("当前FS设备TCP未连接"),
		})
		return
	}

	fse.RunningState = 3 // 正在停止
	_ = fse.UpdateRunningState(3, "正在停止")
	model.WSClientMap.BroadCastEquipRunningState("fse", fse.ID, 3)
	if fse.TcpClient != nil && fse.TcpClient.Connection != nil {
		_ = fse.TcpClient.Connection.Close()
	}
	startTime := time.Now()
	for {
		time.Sleep(100 * time.Millisecond)
		if fse.RunningState == 4 {
			break
		}
		if time.Since(startTime) > time.Second*10 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "停止失败, 停止超时",
				"data": map[string]interface{}{
					"signal_state": fse.RunningState,
					"detail":       fse.Detail,
				},
			})
			return
		}
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"running_state": 4,
		},
	})
}

// FSStatus 获取FS状态
func (con FSController) FSStatus(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前fs_id设备未运行",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"info": fse,
		},
	})
}

// IPRead 读取IP 0101
func (con FSController) IPRead(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP读取", "IP读取", "admin/fs/ip_read", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP读取", "IP读取", "admin/fs/ip_read", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.Stage == 1 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于运行阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	data := model.GenFSFrameData0101()
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP读取", "IP读取", "admin/fs/ip_read", param, 1, "TCP发送失败")
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)
	select {
	case hex := <-tcpRequest.Resp0101:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP读取", "IP读取", "admin/fs/ip_read", param, 0, "success")
	case hex := <-tcpRequest.Resp0181:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "IP读取失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP读取", "IP读取", "admin/fs/ip_read", param, 1, "IP读取失败")
	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "IP读取超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP读取", "IP读取", "admin/fs/ip_read", param, 1, "IP读取超时")
	}

}

// IPWrite 设置IP 0102
func (con FSController) IPWrite(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP设置", "IP设置", "admin/fs/ip_write", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP设置", "IP设置", "admin/fs/ip_write", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.Stage == 1 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于运行阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	data, err := model.GenFSFrameData0102(fse, fse.IP, fse.RedundantIP, uint16(fse.Port), uint16(fse.RedundantPort), fse.RedundantParam1, fse.RedundantParam2, fse.RedundantParam3, fse.RedundantEnable)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "生成帧数据失败" + err.Error(),
			"data":    "GenFSFrameData0102 error",
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP设置", "IP设置", "admin/fs/ip_write", param, 1, "TCP发送失败")
		return
	}
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP设置", "IP设置", "admin/fs/ip_write", param, 1, "TCP发送失败")
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)

	select {
	case hex := <-tcpRequest.Resp0102:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP设置", "IP设置", "admin/fs/ip_write", param, 0, "success")
	case hex := <-tcpRequest.Resp0182:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "IP设置失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP设置", "IP设置", "admin/fs/ip_write", param, 1, "IP设置失败")
	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "IP设置超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "IP设置", "IP设置", "admin/fs/ip_write", param, 1, "IP设置超时")
	}
}

type DownloadApi struct {
	Name   string      `json:"name"`
	Detail string      `json:"detail"`
	Url    string      `json:"url"`
	Params interface{} `json:"params"`
}

// DownloadApiList 获取进度条接口列表
func (con FSController) DownloadApiList(ctx *gin.Context) {
	param := struct {
		FSID       int    `json:"fs_id" binding:"required"`
		ModuleType string `json:"module_type"`
		Apis       string `json:"apis" binding:"required"` // IP读取,IP设置,AI,AQ,DI,DQ,Other...故障诊断
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}

	apiMap := make(map[string]bool)
	dataStr := strings.Split(param.Apis, ",")
	for _, str := range dataStr {
		apiMap[str] = true
	}
	list := make([]*DownloadApi, 0)

	if param.ModuleType != "" {
		// 模块第二层外层, 模块类型层
		url := "admin/fs/module_download"
		if model.AllowModuleCode2[param.ModuleType] != "" {
			url = "admin/fs/module_download"
		} else if model.AllowModelCode2[param.ModuleType] != "" {
			url = "admin/fs/model_download"
		} else {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数 module_type",
				"data": map[string]interface{}{
					"module_type": model.AllowFSCode2,
				},
			})
			return
		}
		codesStr := strings.Split(param.Apis, ",")
		for _, code3 := range codesStr {
			moduleNumber, err2 := strconv.Atoi(code3)
			if err2 != nil {
				ctx.JSON(200, gin.H{
					"code":    2,
					"message": "code3序号转数值失败",
					"data": map[string]interface{}{
						"moduleNumber": moduleNumber,
						"err":          err2.Error(),
					},
				})
				return
			}
			list = append(list, &DownloadApi{Name: param.ModuleType + "下载", Detail: fmt.Sprintf("%s%s下载", param.ModuleType, code3), Url: url, Params: map[string]interface{}{
				"fs_id":         fse.ID,
				"module_type":   param.ModuleType,
				"module_number": moduleNumber,
			}})
		}
	} else {
		// 模块第一层外层
		if apiMap["AI"] {
			putFSDownloadModuleAPI(fse, &list, "AI")
		}
		if apiMap["AQ"] {
			putFSDownloadModuleAPI(fse, &list, "AQ")
		}
		if apiMap["DI"] {
			putFSDownloadModuleAPI(fse, &list, "DI")
		}
		if apiMap["DQ"] {
			putFSDownloadModuleAPI(fse, &list, "DQ")
		}
		if apiMap["Other"] {
			putFSDownloadModuleAPI(fse, &list, "Other")
		}
		if apiMap["泵组电磁阀"] {
			putFSDownloadModelAPI(fse, &list, "泵组电磁阀")
		}
		if apiMap["增压泵电磁阀"] {
			putFSDownloadModelAPI(fse, &list, "增压泵电磁阀")
		}
		if apiMap["电调阀"] {
			putFSDownloadModelAPI(fse, &list, "电调阀")
		}
		if apiMap["压力电磁阀"] {
			putFSDownloadModelAPI(fse, &list, "压力电磁阀")
		}
		if apiMap["电源控制"] {
			putFSDownloadModelAPI(fse, &list, "电源控制")
		}
		if apiMap["电源状态"] {
			putFSDownloadModelAPI(fse, &list, "电源状态")
		}
		if apiMap["模态采集"] {
			putFSDownloadModelAPI(fse, &list, "模态采集")
		}
		if apiMap["故障诊断"] {
			putFSDownloadModelAPI(fse, &list, "故障诊断")
		}
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list": list,
		},
	})
}

// UploadDataScale 单条上载获取数据规模
func (con FSController) UploadDataScale(ctx *gin.Context) {
	param := struct {
		FSID       int    `json:"fs_id" binding:"required"`
		ModuleType string `json:"module_type" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.Stage == 1 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于运行阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	tempFSE, ok2 := model.TempFSMap.Get(param.FSID)
	if !ok2 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "请先读取基本信息~",
			"data":    map[string]interface{}{},
		})
		return
	}
	_, ok2 = model.AllowFSCode2[param.ModuleType]
	if !ok2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 module_type",
			"data": map[string]interface{}{
				"module_type": model.AllowFSCode2,
			},
		})
		return
	}
	apiMap := make(map[string]bool)
	apiMap[param.ModuleType] = true

	if apiMap["AI"] || apiMap["AQ"] || apiMap["DI"] || apiMap["DQ"] || apiMap["OTHER"] {
		if tempFSE.DSModuleRead == 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "请先读取FS基本信息~half",
				"data":    map[string]interface{}{},
			})
			return
		}
	}
	if apiMap["泵组电磁阀"] || apiMap["增压泵电磁阀"] ||
		apiMap["电调阀"] || apiMap["压力电磁阀"] ||
		apiMap["电源控制"] || apiMap["电源状态"] ||
		apiMap["模态采集"] || apiMap["故障诊断"] {
		if tempFSE.DSModelRead == 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "请先读取控制模型基本信息~half",
				"data":    map[string]interface{}{},
			})
			return
		}
	}

	list := make([]map[string]interface{}, 0)

	quantity := 0
	switch param.ModuleType {
	case "AI":
		quantity = int(tempFSE.DS.AI)
	case "AQ":
		quantity = int(tempFSE.DS.AQ)
	case "DI":
		quantity = int(tempFSE.DS.DI)
	case "DQ":
		quantity = int(tempFSE.DS.DQ)
	case "Other":
		quantity = int(tempFSE.DS.Other)
	case "泵组电磁阀":
		quantity = int(tempFSE.DS.Bengzu)
	case "增压泵电磁阀":
		quantity = int(tempFSE.DS.Zengya)
	case "电调阀":
		quantity = int(tempFSE.DS.Diantiao)
	case "压力电磁阀":
		quantity = int(tempFSE.DS.Pressure)
	case "电源控制":
		quantity = int(tempFSE.DS.Power)
	case "电源状态":
		quantity = int(tempFSE.DS.PowerState)
	case "模态采集":
		quantity = int(tempFSE.DS.ModeCollect)
	case "故障诊断":
		quantity = int(tempFSE.DS.Diag)
	}
	for i := 1; i <= quantity; i++ {
		list = append(list, map[string]interface{}{
			"module_type": param.ModuleType,
			"code3":       fmt.Sprintf("%02d", i),
		})
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list": list,
		},
	})
}

func (con FSController) UploadApiList(ctx *gin.Context) {
	param := struct {
		FSID       int    `json:"fs_id" binding:"required"`
		ModuleType string `json:"module_type"`             // 最外层上载这个字段传空字符串, 里层上载这个字段传模块类型 [AI,AQ,DI,DQ,Other...故障诊断] 选一个
		Apis       string `json:"apis" binding:"required"` // 最外层传 "AI,AQ,DI,DQ,Other...故障诊断" 这种逗号拼接格式, 里层传 "01,02,03" 这种逗号拼接格式
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}

	tempFSE, ok2 := model.TempFSMap.Get(param.FSID)
	if !ok2 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "请先读取基本信息~",
			"data":    map[string]interface{}{},
		})
		return
	}

	apiMap := make(map[string]bool)
	if param.ModuleType != "" {
		apiMap[param.ModuleType] = true
	} else {
		dataStr := strings.Split(param.Apis, ",")
		for _, str := range dataStr {
			apiMap[str] = true
		}
	}

	if apiMap["AI"] || apiMap["AQ"] || apiMap["DI"] || apiMap["DQ"] || apiMap["OTHER"] {
		if tempFSE.DSModuleRead == 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "请先读取FS基本信息~half",
				"data":    map[string]interface{}{},
			})
			return
		}
	}
	if apiMap["泵组电磁阀"] || apiMap["增压泵电磁阀"] ||
		apiMap["电调阀"] || apiMap["压力电磁阀"] ||
		apiMap["电源控制"] || apiMap["电源状态"] ||
		apiMap["模态采集"] || apiMap["故障诊断"] {
		if tempFSE.DSModelRead == 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "请先读取控制模型基本信息~half",
				"data":    map[string]interface{}{},
			})
			return
		}
	}

	list := make([]*DownloadApi, 0)

	if param.ModuleType != "" {
		// 模块第二层外层, 模块类型层
		_, ok2 := model.AllowFSCode2[param.ModuleType]
		if !ok2 {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数 module_type",
				"data": map[string]interface{}{
					"module_type": model.AllowFSCode2,
				},
			})
			return
		}
		codesStr := strings.Split(param.Apis, ",")
		for _, code3 := range codesStr {
			moduleNumber, err2 := strconv.Atoi(code3)
			if err2 != nil {
				ctx.JSON(200, gin.H{
					"code":    2,
					"message": "code3序号转数值失败",
					"data": map[string]interface{}{
						"moduleNumber": moduleNumber,
						"err":          err2.Error(),
					},
				})
				return
			}
			url := ""
			switch param.ModuleType {
			case "AI":
				fallthrough
			case "AQ":
				fallthrough
			case "DI":
				fallthrough
			case "DQ":
				fallthrough
			case "Other":
				url = "admin/fs/module_upload"
			case "泵组电磁阀":
				fallthrough
			case "增压泵电磁阀":
				fallthrough
			case "电调阀":
				fallthrough
			case "压力电磁阀":
				fallthrough
			case "电源控制":
				fallthrough
			case "电源状态":
				fallthrough
			case "模态采集":
				fallthrough
			case "故障诊断":
				url = "admin/fs/model_upload"
			}
			list = append(list, &DownloadApi{Name: param.ModuleType + "上载", Detail: fmt.Sprintf("%s%s上载", param.ModuleType, code3), Url: url, Params: map[string]interface{}{
				"fs_id":         fse.ID,
				"module_type":   param.ModuleType,
				"module_number": moduleNumber,
			}})
		}
	} else {
		// 第一层
		if apiMap["AI"] {
			putFSModuleUploadAPI(tempFSE, &list, "AI", tempFSE.DS.AI)
		}
		if apiMap["AQ"] {
			putFSModuleUploadAPI(tempFSE, &list, "AQ", tempFSE.DS.AQ)
		}
		if apiMap["DI"] {
			putFSModuleUploadAPI(tempFSE, &list, "DI", tempFSE.DS.DI)
		}
		if apiMap["DQ"] {
			putFSModuleUploadAPI(tempFSE, &list, "DQ", tempFSE.DS.DQ)
		}
		if apiMap["Other"] {
			putFSModuleUploadAPI(tempFSE, &list, "Other", tempFSE.DS.Other)
		}
		if apiMap["泵组电磁阀"] {
			putFSModelUploadAPI(tempFSE, &list, "泵组电磁阀", tempFSE.DS.Bengzu)
		}
		if apiMap["增压泵电磁阀"] {
			putFSModelUploadAPI(tempFSE, &list, "增压泵电磁阀", tempFSE.DS.Zengya)
		}
		if apiMap["电调阀"] {
			putFSModelUploadAPI(tempFSE, &list, "电调阀", tempFSE.DS.Diantiao)
		}
		if apiMap["压力电磁阀"] {
			putFSModelUploadAPI(tempFSE, &list, "压力电磁阀", tempFSE.DS.Pressure)
		}
		if apiMap["电源控制"] {
			putFSModelUploadAPI(tempFSE, &list, "电源控制", tempFSE.DS.Power)
		}
		if apiMap["电源状态"] {
			putFSModelUploadAPI(tempFSE, &list, "电源状态", tempFSE.DS.PowerState)
		}
		if apiMap["模态采集"] {
			putFSModelUploadAPI(tempFSE, &list, "模态采集", tempFSE.DS.ModeCollect)
		}
		if apiMap["故障诊断"] {
			putFSModelUploadAPI(tempFSE, &list, "故障诊断", tempFSE.DS.Diag)
		}
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list": list,
		},
	})
}

// DownloadHistoryLog 模块模型下载历史记录
func (con FSController) DownloadHistoryLog(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID   int    `json:"fs_id" binding:"required"`
		Search string `json:"search" binding:"max=50"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	tx := model.DB.Where("project_id = ?", userToken.ProjectID)
	if param.FSID != 0 {
		tx.Where("fs_id = ?", param.FSID)
	}
	var count int64
	list := make([]*model.CommandHistory, 0)
	err = tx.Model(&model.CommandHistory{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Preload("FSInfo").Order("id ASC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

// FirstHandShake 运行首次握手指令 0601
func (con FSController) FirstHandShake(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.Stage == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于组态阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	data := model.GenFSFrameData0601()
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)

	select {
	case hex := <-tcpRequest.Resp0601:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "握手成功",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
	case hex := <-tcpRequest.Resp0681:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "握手失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "握手超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
	}
}

// FirstSync 运行首次同步发送指令 0602, 返回所有数据规模数据和限值
func (con FSController) FirstSync(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.Stage == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于组态阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.DSMatched == 1 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "当前设备已进入循环运行同步中, 不可操作",
			"data": map[string]interface{}{
				"ds": fse.DS,
			},
		})
		return
	}
	data := model.GenFSFrameData0602()
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)

	select {
	case hex := <-tcpRequest.Resp0602:
		if hex == "ok" {
			ctx.JSON(200, gin.H{
				"code":    0,
				"message": "数据规模一致",
				"data":    map[string]interface{}{},
			})
		} else {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": hex,
				"data":    map[string]interface{}{},
			})
		}
	case hex := <-tcpRequest.Resp0612:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "首次运行同步返回限值成功",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
	case hex := <-tcpRequest.Resp0682:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "首次运行同步失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})

	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "首次运行同步超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
	}
}

// Sync 运行同步发送指令 0603, 只返回所有数据规模数据
func (con FSController) Sync(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.Stage == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于组态阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.DSMatched == 0 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "FS设备数据规模不匹配",
		})
		return
	}
	data := model.GenFSFrameData0603(fse)
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)

	select {
	case hex := <-tcpRequest.Resp0603:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "同步发送返回模块成功",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
	case hex := <-tcpRequest.Resp0683:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "同步发送失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})

	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "同步发送超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
	}
}

// BasicRead FS基本信息读取 0401
func (con FSController) BasicRead(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.Stage == 1 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于运行阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	data := model.GenFSFrameData0401()
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)

	select {
	case hex := <-tcpRequest.Resp0401:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "读取成功",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
	case hex := <-tcpRequest.Resp0481:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "读取错误",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})

	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "读取超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
	}
}

// ModelRead 模型控制信息读取 0501
func (con FSController) ModelRead(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.Stage == 1 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于运行阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	data := model.GenFSFrameData0501()
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)

	select {
	case hex := <-tcpRequest.Resp0501:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "读取成功",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
	case hex := <-tcpRequest.Resp0581:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "读取错误",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})

	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "读取超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
	}
}

// RunSyncModifyModuleValue 修改AI等模块的值 0604
func (con FSController) RunSyncModifyModuleValue(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID    int    `json:"fs_id" binding:"required"`
		Content string `json:"content" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	list := make([]*model.DataPart0604, 0)
	err = json.Unmarshal([]byte(param.Content), &list)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "json解析失败 content",
			"data":    err.Error(),
		})
		return
	}
	if len(list) == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "content不可为空",
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "修改模块模型值", "修改模块模型值", "admin/fs/run_sync_modify_module_value", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "修改模块模型值", "修改模块模型值", "admin/fs/run_sync_modify_module_value", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.Stage == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备处于组态阶段, 不可操作",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.DSMatched == 0 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "FS设备数据规模不匹配",
		})
		return
	}
	err = validateDataPart0604(fse, list)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "content校验失败: " + err.Error(),
		})
		return
	}
	data, err := model.GenFSFrameData0604(fse, list)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "生成数据帧失败0604: " + err.Error(),
		})
		return
	}
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "TCP发送失败",
			"data":    err.Error(),
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "修改模块模型值", "修改模块模型值", "admin/fs/run_sync_modify_module_value", param, 1, "TCP发送失败")
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)
	select {
	case hex := <-tcpRequest.Resp0604:
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "修改模块模型值", "修改模块模型值", "admin/fs/run_sync_modify_module_value", param, 0, "success")
	case hex := <-tcpRequest.Resp0684:
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "修改模块模型值失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "修改模块模型值", "修改模块模型值", "admin/fs/run_sync_modify_module_value", param, 1, "修改模块模型值失败")
	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "修改模块模型值超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
		_ = model.CommandHistoryLog(1, userToken.ProjectID, param.FSID, "修改模块模型值", "修改模块模型值", "admin/fs/run_sync_modify_module_value", param, 1, "修改模块模型值超时")
	}
}

func (con FSController) UploadHistoryList(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID       int    `json:"fs_id"`
		ModuleType string `json:"module_type"`
		Status     uint8  `json:"status"`
		Slim       uint8  `json:"slim"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Where("project_id = ?", userToken.ProjectID)
	if param.FSID != 0 {
		tx.Where("fs_id = ?", param.FSID)
	}
	if param.ModuleType != "" {
		tx.Where("module_type = ?", param.ModuleType)
	}
	if param.Status != 0 {
		tx.Where("status = ?", param.Status)
	}
	if param.Search != "" {
		if len([]rune(param.Search)) > 30 {
			tx.Where("detail like ? ", "%"+param.Search+"%")
		} else {
			tx.Where("name like ? OR detail like ?", "%"+param.Search+"%", "%"+param.Search+"%")
		}
	}
	if param.StartTime != "" {
		tx.Where("create_time >= ?", param.StartTime)
	}
	if param.EndTime != "" {
		tx.Where("create_time <= ?", param.EndTime)
	}

	var count int64
	list := make([]model.UploadHistory, 0)
	err = tx.Model(&model.UploadHistory{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	if param.Slim == 1 {
		err = tx.Preload("FSEInfo").Preload("ProjectInfo").Omit("data").Order("id DESC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	} else {
		err = tx.Preload("FSEInfo").Preload("ProjectInfo").Order("id DESC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	}
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

func (con FSController) UploadHistoryHandle(ctx *gin.Context) {
	param := struct {
		ID     int   `json:"id" binding:"required"`
		Status uint8 `json:"status" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	if param.Status != 2 && param.Status != 3 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数status",
			"data":    "",
		})
		return
	}
	if param.Status == 2 { // 进行覆盖操作
		info := &model.UploadHistory{}
		err = model.DB.Where("id = ?", param.ID).First(info).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		if info.Status != 1 {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "当前数据状态不可进行覆盖操作",
			})
			return
		}
		fse := &model.FSEquip{}
		exist, err2 := fse.Exists(info.FSID)
		if !exist {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数 fs_id",
				"data":    err2,
			})
			return
		}
		_, _, err = model.UploadHistoryHandleExecute(fse, info)
	}
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    10,
			"message": err.Error(),
		})
		return
	}
	updateData := make(map[string]interface{})
	updateData["status"] = param.Status
	updateData["update_time"] = tools.GetNow()
	err = model.DB.Model(&model.UploadHistory{}).Where("id = ? AND status = 1", param.ID).Updates(updateData).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con FSController) UploadHistoryHandleMulti(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		IDS    string `json:"ids" binding:""`
		Status uint8  `json:"status" binding:"required"` // 2.覆盖 3.忽略
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if param.Status != 2 && param.Status != 3 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数status",
			"data":    "",
		})
		return
	}
	ids := tools.StrToIntSlice(param.IDS)
	list := make([]*model.UploadHistory, 0)
	if param.IDS == "" {
		err = model.DB.Where("project_id = ? AND status = 1", userToken.ProjectID).Order("id ASC").Limit(500).Find(&list).Error
	} else {
		err = model.DB.Where("project_id = ? AND status = 1 AND id in ?", userToken.ProjectID, ids).Order("id ASC").Limit(500).Find(&list).Error
	}
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	resultList := make([]map[string]interface{}, 0)
	for _, info := range list {
		if param.Status == 2 {
			fse := &model.FSEquip{}
			exist, err := fse.Exists(info.FSID)
			if !exist {
				resultList = append(resultList, map[string]interface{}{
					"id":            info.Id,
					"fs_id":         info.FSID,
					"module_type":   info.ModuleType,
					"module_number": info.ModuleNumber,
					"result":        fmt.Sprintf("exception %v", err),
				})
				continue
			}
			_, _, err = model.UploadHistoryHandleExecute(fse, info)
			if err != nil {
				resultList = append(resultList, map[string]interface{}{
					"id":            info.Id,
					"fs_id":         info.FSID,
					"module_type":   info.ModuleType,
					"module_number": info.ModuleNumber,
					"result":        fmt.Sprintf("%v", err),
				})
				continue
			}
		}

		updateData := make(map[string]interface{})
		updateData["status"] = param.Status
		updateData["update_time"] = tools.GetNow()
		err = model.DB.Model(&model.UploadHistory{}).Where("id = ?", info.Id).Updates(updateData).Error
		if err != nil {
			resultList = append(resultList, map[string]interface{}{
				"id":            info.Id,
				"fs_id":         info.FSID,
				"module_type":   info.ModuleType,
				"module_number": info.ModuleNumber,
				"result":        fmt.Sprintf("update %v", err),
			})
		}
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"result": resultList,
		},
	})
}
